package com.pine.dbant.core.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.List;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    private static final String[] CLASSPATH_RESOURCE_LOCATIONS = {
            "classpath:/META-INF/resources/", "classpath:/resources/",
            "classpath:/static/", "classpath:/public/","classpath:/editor/"
    };

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**")
                .addResourceLocations(CLASSPATH_RESOURCE_LOCATIONS);
        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");

    }

    /**
     * 支持REST接口请求入参的自定义转换器
     * @param registry 注册器
     */
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // 支持将请求参数时间格式String转为Date
        registry.addConverter(new DateConverter());
    }

    /**
     * 添加到消息转换器
     * 支持json返回到前台时，自定义的配置（忽略null)
     */
    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        // 因为继承WebMvcConfigurationSupport后，会让application.yml中的jackson配置non_null失效，因此这里加入自定义的json转换器重新配置
        // 添加我们自定义的 HttpMessageConverter, 优先级最高
        converters.add(0, jackson2HttpMessageConverter());
    }

    /**
     * 处理返回json格式
     * POJO对象返回给前端，转为json时，忽略null的属性，节约网络流量
     * @return MappingJackson2HttpMessageConverter
     */
    @Bean
    public MappingJackson2HttpMessageConverter jackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = new ObjectMapper();
        //在反序列化时忽略在 json 中存在但 Java 对象不存在的属性
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        //在序列化时忽略值为 null 的属性
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 【不做时间格式化】  【注意！不要做时间格式化，经过和前端协商，后台统一返回时间戳的格式，避免BUG】 comment by huangli 2020.11.24
        // 默认返回时间戳，若加上下面这句，则在序列化时日期格式为 yyyy-MM-dd'T'HH:mm:ss.SSSZ
        // mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
        // }} 【不做时间格式化】

        // 支持JSR-310 LocalDate, LocaDateTime转为json, 2022.5.13 by huangli DashboardV2相关接口需要
        // 默认格式为 2021-02-01T03:04:05+8
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ISO_DATE_TIME));
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_DATE));
        javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ISO_TIME));
        javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ISO_DATE_TIME));
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_DATE));
        javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_TIME));

        mapper.registerModule(javaTimeModule);
        converter.setObjectMapper(mapper);
        return converter;
    }
}
